home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 January: Mac OS SDK / Dev.CD Jan 96 SDK / Dev.CD Jan 96 SDK1.toast / Development Kits (Disc 1) / AOCE / Development Tools / Sample Code / Messaging Service Access Module / Internet PMSAM / Internet PMSAM source / gatewaystuff.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-10-29  |  19.2 KB  |  771 lines  |  [TEXT/MPS ]

  1. /*-------------------------------------------------------------------
  2.  
  3. AOCE Post Office Protocol (POP) / Simple Mail Transfer Protocol (SMTP)
  4. Mail Service Access Module
  5.  
  6. written by Steve Falkenburg-- MacDTS
  7. ©1991-1993 Apple Computer, Inc.
  8.  
  9. --------------
  10. change history
  11. --------------
  12.  
  13. SJF        02/19/93    update for beta build    b1
  14. SJF        10/29/92    update to a11            a11
  15. SJF        06/08/92    update to a8            a8
  16. SJF        02/15/92    first working version    a4.5
  17. SJF        10/16/91    initial coding            a3
  18.  
  19. ---------------------------------------------------------------------*/
  20.  
  21. #ifndef __TRAPS__
  22. #include <Traps.h>
  23. #endif
  24.  
  25. #ifndef __GESTALTEQU__
  26. #include <GestaltEqu.h>
  27. #endif
  28.  
  29. #ifndef __OCE__
  30. #include <OCE.h>
  31. #endif
  32.  
  33. #ifndef __OCEAUTHDIR__
  34. #include <OCEAuthDir.h>
  35. #endif
  36.  
  37. #ifndef __OCEERRORS__
  38. #include <OCEErrors.h>
  39. #endif
  40.  
  41. #include <string.h>
  42.  
  43. #ifdef applec
  44. #include <strings.h>
  45. #endif
  46.  
  47. #include "const.h"
  48. #include "gwerrors.h"
  49. #include "mytypes.h"
  50. #include "globals.h"
  51. #include "utils.h"
  52. #include "trapavailable.h"
  53. #include "authstuff.h"
  54. #include "gatewaystuff.h"
  55.  
  56.  
  57. // think c compatibility
  58. #ifndef    _GestaltDispatch
  59. #define    _GestaltDispatch    _Gestalt
  60. #endif
  61.  
  62.  
  63. // InitGatewayStuff
  64. //
  65. // called when the gateway is first launched.  initializes the global variables of importance
  66. // to AOCE and reads in the slot information for all of the gateways slots.
  67. //
  68. OSErr InitGatewayStuff(void)
  69. {
  70.     OSErr err;
  71.     DirParamBlock dirBlock;
  72.     MSAMParam msBlock;
  73.     
  74.     gHLEventAdd = gHLEventRemove = nil;
  75.     
  76.     gNumSlots = 0;
  77.         
  78.     // get the local identity for dir manager calls
  79.  
  80.     err = InitAuthStuff();
  81.     if (err!=noErr)
  82.         return err;
  83.         
  84.     // get creation ID of the AOCE setup PAB
  85.     
  86.     err = DirGetOCESetupRefNum(&dirBlock,false);
  87.     if (err!=noErr) {
  88.         ExitAuthStuff();
  89.         return err;
  90.     }
  91.     
  92.     OCECopyCreationID(&dirBlock.dirGetOCESetupRefNumPB.oceSetupRecordCID,&gAOCESetupCID);
  93.     gAOCESetupDSRef = dirBlock.dirGetOCESetupRefNumPB.dsRefNum;
  94.     
  95.     // get location
  96.     
  97.     err = GetSingleValueAttribute(&gAOCESetupCID,OCEGetIndAttributeType(kLocationAttrTypeNum),
  98.             &gLocation,sizeof(OCESetupLocation));
  99.     if (err!=noErr)
  100.         return err;
  101.         
  102.     // get creation ID of gateway setup record
  103.     
  104.     err = PMSAMGetMSAMRecord(&msBlock);
  105.     if (err!=noErr) {
  106.         ExitAuthStuff();
  107.         return err;
  108.     }
  109.     OCECopyCreationID(&msBlock.pmsamGetMSAMRecord.msamCID,&gMSAMCID);
  110.  
  111.     // read slot info    
  112.     
  113.     err = ReadGatewaySlotInformation();
  114.     if (err==kMailNoSuchSlot) {
  115. #ifdef kDEBUG
  116.         DebugStr("\pQueue not registered yet, but we'll continue anyway, since it will be sometime");
  117. #endif
  118.         MarkSlotInformationDirty();
  119.         err = noErr;
  120.     }
  121.     
  122.     if (err!=noErr) {
  123.         ExitAuthStuff();
  124.         return err;
  125.     }
  126.     
  127.     gAOCEInited = true;
  128.     
  129.     return err;
  130. }
  131.  
  132.  
  133. // ActivateSlot
  134. //
  135. // sets up a slot spec as active and ready to accept mail, this call gets refs to the in and out
  136. // queues for the slot
  137. //
  138. OSErr ActivateSlot(SlotSpec *slot)
  139. {
  140.     MSAMParam msParam;
  141.     OSErr err;
  142.     
  143.     // get slot queues
  144.         
  145.     msParam.pmsamOpenQueues.msamSlotID = slot->slotID;
  146.     err = PMSAMOpenQueues(&msParam);
  147.     
  148.     // set up other slot info
  149.     
  150.     slot->inQueue = msParam.pmsamOpenQueues.inQueueRef;
  151.     slot->outQueue = msParam.pmsamOpenQueues.outQueueRef;
  152.     slot->lastCheckGet = 0;
  153.     slot->lastCheckPut = 0;
  154.     slot->enabled = true;
  155.     slot->retryPut = 0;
  156.     slot->retryGet = 0;
  157.     slot->retryPutError = 0;
  158.     slot->retryGetError = 0;
  159.  
  160.     if (err!=noErr) {
  161.         slot->enabled = false;
  162.     }
  163.  
  164.     return err;
  165. }
  166.  
  167.  
  168. // CheckSlotRefresh
  169. //
  170. // called when we need to see if the slot information needs to be updated.  calls
  171. // ReadGatewaySlotInformation to re-read the information
  172. //
  173. OSErr CheckSlotRefresh(void)
  174. {
  175.     OSErr err;
  176.     
  177.     err = noErr;
  178.     
  179.     if (gUpdateSlotInformation) {
  180.         err = ReadGatewaySlotInformation();
  181.         if (err==kMailNoSuchSlot) {
  182.             // no queue for our slot yet... try again later.
  183.             err = noErr;
  184. #ifdef kDEBUG
  185.             DebugStr("\pno queue yet... try again later");
  186. #endif
  187.             MarkSlotInformationDirty();
  188.         }
  189.     }
  190.     return err;
  191. }
  192.  
  193.  
  194. // MarkSlotInformationDirty
  195. //
  196. // marks the slot database for refresh at main event loop time
  197. //
  198. void MarkSlotInformationDirty(void)
  199. {
  200.     gUpdateSlotInformation = true;
  201. }
  202.  
  203.  
  204. // ReadGatewaySlotInformation
  205. // 
  206. // called in response to a launch *or* in response to a change in the slot database,
  207. // this call rebuilds the internal database of slots from the AOCE Setup Directory
  208. //
  209. OSErr ReadGatewaySlotInformation(void)
  210. {
  211.     short slotIndex;
  212.     OSErr err;
  213.     
  214.     TraceExecution("\pReadGatewaySlotInformation");
  215.  
  216.     gUpdateSlotInformation = false;
  217.     gNumSlots = 0;
  218.     
  219.     // set up the skeleton slot database containing only the CID to the mailservice records
  220.     
  221.     err = GetParseAttributes(&gMSAMCID,kMailServiceAttrTypeNum,AddSlotCallback,0L);
  222.     if (err!=noErr)
  223.         return err;
  224.     
  225.     // for each slot, get the slot data from the mailservice record and activate the slot
  226.     
  227.     for (slotIndex=0;slotIndex<gNumSlots && err==noErr;slotIndex++) {
  228.         err = GetMailServiceInfo(&gSlotDatabase[slotIndex].slotCID,&gSlotDatabase[slotIndex]);
  229.         if (err==noErr)
  230.             err = ActivateSlot(&gSlotDatabase[slotIndex]);
  231.     }
  232.     
  233.     gAuthRefresh = true;    // re-read the directory external identities
  234.     
  235.     if (gAOCEInited && (gNumSlots==0)) {    // if we don't have any slots, and we didn't just launch,
  236.         gDone = true;                        // then quit MSAM
  237. #ifdef kDEBUG
  238.         DebugStr("\pexiting since no slots");
  239. #endif
  240.     }
  241.             
  242.     return err;
  243. }
  244.  
  245.  
  246. // GetMailServiceInfo
  247. //
  248. // given a creation ID to a mailservice record ID and a storage area in the slot database, this function fills
  249. // in the slot database information for a particular slot.
  250. //
  251. OSErr GetMailServiceInfo(CreationID *cid,SlotSpecPtr theSlot)
  252. {
  253.     PackedRecordID packedAssocDir;
  254.     RecordID assocDir;
  255.     CreationID *dirCID;
  256.     OSErr err;
  257.     OSType dirType;
  258.     RString comment;
  259.     AttributeType attrTypeString;
  260.     
  261.     // get slot id
  262.     
  263.     err = GetSingleValueAttribute(cid,OCEGetIndAttributeType(kSlotIDAttrTypeNum),&theSlot->slotID,sizeof(short));
  264.     if (err!=noErr)
  265.         return err;
  266.     
  267.     // get standard slot information
  268.     
  269.     err = GetSingleValueAttribute(cid,OCEGetIndAttributeType(kStdSlotInfoAttrTypeNum),&theSlot->stdInfo,sizeof(MailStandardSlotInfoAttribute));
  270.     if (err!=noErr)
  271.         return err;
  272.     theSlot->locationActive = theSlot->stdInfo.active;
  273.     
  274.     // get associated directory
  275.     
  276.     err = GetSingleValueAttribute(cid,OCEGetIndAttributeType(kAssoDirectoryAttrTypeNum),&packedAssocDir,sizeof(PackedRecordID));
  277.     if (err!=noErr)
  278.         return err;
  279.  
  280.     // get info from associated directory
  281.     
  282.     OCEUnpackRecordID(&packedAssocDir,&assocDir);
  283.     dirCID = &assocDir.local.cid;
  284.     
  285.     // get directory type
  286.         
  287.     err = GetSingleValueAttribute(dirCID,OCEGetIndAttributeType(kDirTypeAttrTypeNum),&dirType,sizeof(OSType));
  288.     if (err!=noErr)
  289.         return err;
  290.     
  291.     // get directory name
  292.     
  293.     err = GetSingleValueAttribute(dirCID,OCEGetIndAttributeType(kRealNameAttrTypeNum),&theSlot->directoryName,sizeof(RString));
  294.     if (err!=noErr)
  295.         return err;
  296.     
  297.     // get directory discriminator
  298.     
  299.     err = GetSingleValueAttribute(dirCID,OCEGetIndAttributeType(kDiscriminatorAttrTypeNum),
  300.         &theSlot->discriminator,sizeof(DirDiscriminator));
  301.     if (err!=noErr)
  302.         return err;
  303.  
  304.     // get directory comment
  305.     
  306.     err = GetSingleValueAttribute(dirCID,OCEGetIndAttributeType(kCommentAttrTypeNum),&comment,sizeof(RString));
  307.     if (err!=noErr)
  308.         return err;
  309.     
  310.     //
  311.     // code to get specific slot information
  312.     //
  313.     
  314.     // now we get all the specific information at the same time
  315.         
  316.     OCECToRString(kSpecInfoAttr,smRoman,(RString*)&attrTypeString,kRStringMaxBytes);
  317.     err = GetSingleValueAttribute(cid,&attrTypeString,&theSlot->specInfo,sizeof(SpecificSlotInfo));
  318.     if (err!=noErr)
  319.         return err;
  320.     
  321.     // note that we don't get the name and password -- these are filled in by the auth mgr
  322.     // refresh mechanism, dispatched by setting a flag from the auth mgr queue notification
  323.     // proc, and filled in at event loop time
  324.     
  325.     theSlot->dirIdentity.userName[0] = 0;
  326.     theSlot->dirIdentity.password[0] = 0;
  327.     theSlot->dirIdentity.valid = false;
  328.     
  329.     return err;
  330. }
  331.  
  332.  
  333. // GetParseAttributes
  334. //
  335. // this routine provides a generic lookup routine to iterate through attributes in a
  336. // personal directory record.  it's used to read the slot setup information out of the
  337. // aoce setup directory
  338. //
  339. OSErr GetParseAttributes(CreationID *cid,short attrType,ForEachAttrValue callBack,long clientData)
  340. {
  341.     DirParamBlock dirBlock;
  342.     Ptr buff;
  343.     Boolean moreData;
  344.     OSErr err;
  345.     RecordIDPtr recordList[1];
  346.     AttributeTypePtr attrList[1];
  347.     RecordID recordID;
  348.     
  349.     MakePersonalRecordID(&recordID,cid);
  350.     
  351.     recordList[0] = (RecordIDPtr)&recordID;
  352.     attrList[0] = OCEGetIndAttributeType(attrType);
  353.     buff = NewPtrChk(kAttrBufferSize);
  354.     if (MemError()!=noErr)
  355.         return MemError();
  356.     
  357.     ClearBuffer(&dirBlock,sizeof(DirParamBlock));
  358.         
  359.     dirBlock.header.clientData = clientData;
  360.     dirBlock.lookupGetPB.serverHint.aNet = 0;
  361.     dirBlock.lookupGetPB.serverHint.aNode = 0;
  362.     dirBlock.lookupGetPB.serverHint.aSocket = 0;
  363.     dirBlock.lookupGetPB.dsRefNum = gAOCESetupDSRef;
  364.     dirBlock.lookupGetPB.identity = gLocalIdentity;
  365.     dirBlock.lookupGetPB.aRecordList = recordList;
  366.     dirBlock.lookupGetPB.attrTypeList = attrList;
  367.     dirBlock.lookupGetPB.recordIDCount = 1;
  368.     dirBlock.lookupGetPB.attrTypeCount = 1;
  369.     dirBlock.lookupGetPB.includeStartingPoint = false;
  370.     dirBlock.lookupGetPB.getBuffer = buff;
  371.     dirBlock.lookupGetPB.getBufferSize = kAttrBufferSize;
  372.     dirBlock.lookupGetPB.startingRecordIndex = 1;
  373.     dirBlock.lookupGetPB.startingAttrTypeIndex = 1;
  374.     dirBlock.lookupParsePB.eachRecordID = nil;
  375.     dirBlock.lookupParsePB.eachAttrType = nil;
  376.     dirBlock.lookupParsePB.eachAttrValue = callBack;
  377.     OCESetCreationIDtoNull(&dirBlock.lookupGetPB.startingAttribute.cid);
  378.     
  379.     do {
  380.         err = DirLookupGet(&dirBlock,false);
  381.         if (err==kOCEMoreData)
  382.             moreData = true;
  383.         else
  384.             moreData = false;
  385.         if (err==noErr || err==kOCEMoreData) {
  386.             err = DirLookupParse(&dirBlock,false);
  387.             if (err!=noErr)
  388.                 moreData = false;    // this could be kOCEMoreAttrValue (buffer not big enough)
  389.                                     // or kOCEMoreData (didn't have permission to read)
  390.         }
  391.     } while (moreData);
  392.     
  393.     DisposPtrChk(buff);
  394.     
  395.     return err;
  396. }
  397.  
  398.  
  399. // GetSingleValueAttribute
  400. //
  401. // this routine returns a single attribute value from a record.  it's used to get information out
  402. // of the slot setup information
  403. //
  404. OSErr GetSingleValueAttribute(CreationID *cid,AttributeType *attribType,void *attrBuffer,Size attrBufferSize)
  405. {
  406.     DirParamBlock dirBlock;
  407.     Ptr buff;
  408.     OSErr err;
  409.     RecordIDPtr recordList[1];
  410.     AttributeTypePtr attrList[1];
  411.     RecordID recordID;
  412.     AttributeCopyInfo callbackInfo;
  413.     
  414.     callbackInfo.buffer = attrBuffer;
  415.     callbackInfo.bufferSize = attrBufferSize;
  416.     
  417.     MakePersonalRecordID(&recordID,cid);
  418.     
  419.     recordList[0] = (RecordIDPtr)&recordID;
  420.     attrList[0] = attribType;
  421.     buff = NewPtrChk(kAttrBufferSize);
  422.     if (MemError()!=noErr)
  423.         return MemError();
  424.     
  425.     ClearBuffer(&dirBlock,sizeof(DirParamBlock));
  426.         
  427.     dirBlock.header.clientData = (long)&callbackInfo;
  428.     dirBlock.lookupGetPB.serverHint.aNet = 0;
  429.     dirBlock.lookupGetPB.serverHint.aNode = 0;
  430.     dirBlock.lookupGetPB.serverHint.aSocket = 0;
  431.     dirBlock.lookupGetPB.dsRefNum = gAOCESetupDSRef;
  432.     dirBlock.lookupGetPB.identity = gLocalIdentity;
  433.     dirBlock.lookupGetPB.aRecordList = recordList;
  434.     dirBlock.lookupGetPB.attrTypeList = attrList;
  435.     dirBlock.lookupGetPB.recordIDCount = 1;
  436.     dirBlock.lookupGetPB.attrTypeCount = 1;
  437.     dirBlock.lookupGetPB.includeStartingPoint = false;
  438.     dirBlock.lookupGetPB.getBuffer = buff;
  439.     dirBlock.lookupGetPB.getBufferSize = kAttrBufferSize;
  440.     dirBlock.lookupGetPB.startingRecordIndex = 1;
  441.     dirBlock.lookupGetPB.startingAttrTypeIndex = 1;
  442.     dirBlock.lookupParsePB.eachRecordID = RecordIDCallback;
  443.     dirBlock.lookupParsePB.eachAttrType = nil;
  444.     dirBlock.lookupParsePB.eachAttrValue = SingleAttrValueCallback;
  445.     OCESetCreationIDtoNull(&dirBlock.lookupGetPB.startingAttribute.cid);
  446.     
  447.     err = DirLookupGet(&dirBlock,false);
  448.     if (err==noErr || err==kOCEMoreData)
  449.         err = DirLookupParse(&dirBlock,false);
  450.     
  451.     DisposPtrChk(buff);
  452.     return err;
  453. }
  454.  
  455.  
  456. pascal Boolean RecordIDCallback(long clientData, const RecordID *recordID)
  457. {
  458.     #pragma unused (clientData,recordID)
  459.     
  460.     return false;
  461. }
  462.  
  463.  
  464. pascal Boolean SingleAttrValueCallback(long clientData, const Attribute *attribute)
  465. {
  466.     AttributeCopyInfoPtr callbackInfo;
  467.     Size moveSize;
  468.     
  469.     callbackInfo = (AttributeCopyInfoPtr) clientData;
  470.     
  471.     moveSize = attribute->value.dataLength;
  472.     if (moveSize>callbackInfo->bufferSize)
  473.         moveSize = callbackInfo->bufferSize;
  474.     BlockMove(attribute->value.bytes,callbackInfo->buffer,moveSize);
  475.     return false;
  476. }
  477.  
  478.  
  479. pascal Boolean AddSlotCallback(long clientData, const Attribute *attribute)
  480. {
  481.     #pragma unused (clientData)
  482.     SlotSpec *newSlot;
  483.     PackedRecordIDPtr packedRID;
  484.     RecordID rid;
  485.     
  486.     newSlot = &gSlotDatabase[gNumSlots++];
  487.     
  488.     packedRID = (PackedRecordIDPtr) attribute->value.bytes;
  489.     OCEUnpackRecordID(packedRID,&rid);
  490.     OCECopyCreationID(&rid.local.cid,&newSlot->slotCID);
  491.  
  492.     return false;    // continue
  493. }
  494.  
  495.  
  496. pascal Boolean SearchCallback(long clientData, const Attribute *attribute)
  497. {
  498.     AttributeCopyInfoPtr callbackInfo;
  499.     PackedRecordIDPtr packedRID;
  500.     RecordID rid;
  501.     short checkMatch;
  502.     
  503.     callbackInfo = (AttributeCopyInfoPtr)clientData;
  504.     
  505.     if (callbackInfo->bufferSize!=attribute->value.dataLength)
  506.         return false;        // continue the search- lengths don't match
  507.         
  508.     for (checkMatch=0; checkMatch<callbackInfo->bufferSize; checkMatch++) {
  509.         if (attribute->value.bytes[checkMatch]!=callbackInfo->buffer[checkMatch])
  510.             return false;    // continue the search
  511.     }
  512.     
  513.     // copy the attribute CID
  514.     
  515.     OCECopyCreationID(&attribute->cid,&callbackInfo->cid);
  516.     
  517.     return true;    // end the search - we found the match
  518. }
  519.  
  520.  
  521. // AddAttribute
  522. //
  523. // add an attribute value to a record
  524. //
  525. // note: this can be can be called in response to an EPPC handled by the "alternate" event loop
  526. //       this is why we 
  527. OSErr AddAttribute(CreationID *cid,short dsRef,AttributeType *attribType,void *data,unsigned long dataLength,AttributeTag tag)
  528. {
  529.     DirParamBlock attrBlock;
  530.     RecordID recordID;
  531.     Attribute attribute;
  532.     OSErr err;
  533.     
  534.     MakePersonalRecordID(&recordID,cid);    
  535.     
  536.     attrBlock.addAttributeValuePB.serverHint.aNet = 0;
  537.     attrBlock.addAttributeValuePB.serverHint.aNode = 0;
  538.     attrBlock.addAttributeValuePB.serverHint.aSocket = 0;
  539.     attrBlock.addAttributeValuePB.dsRefNum = dsRef;
  540.     attrBlock.addAttributeValuePB.identity = gLocalIdentity;
  541.     attrBlock.addAttributeValuePB.aRecord = &recordID;
  542.     attrBlock.addAttributeValuePB.attr = &attribute;
  543.  
  544.     ClearBuffer(&attribute,sizeof(Attribute));
  545.     err = OCECopyRString((const RString *)attribType, (RString *)&attribute.attributeType,kAttributeTypeMaxBytes);
  546.     if (err!=noErr)
  547.         return err;
  548.     attribute.value.tag = tag;
  549.     attribute.value.dataLength = dataLength;
  550.     attribute.value.bytes = (Ptr)data;
  551.     err = DirAddAttributeValue(&attrBlock,false);
  552.  
  553.     return err;
  554. }
  555.  
  556.  
  557. // GetSingleRecord
  558. //
  559. // returns the RecordID for a record of a given type, if it matches the name you were
  560. // looking for which is passed in
  561. //
  562. OSErr GetSingleRecord(short dsRef,RStringPtr recordType,RStringPtr recordName,CreationID *returnedCID)
  563. {
  564.     DirParamBlock dirBlock;
  565.     Ptr buff;
  566.     char *blank;
  567.     RStringPtr typesList[1];
  568.     OSErr err;
  569.     RecordCopyInfo recCopyInfo;
  570.     
  571.     buff = NewPtr(kRecordBufferSize);
  572.     if (MemError()!=noErr)
  573.         return MemError();
  574.  
  575.     for (blank=(char*)&dirBlock;(blank-(char*)&dirBlock)<sizeof(DirParamBlock);blank++)
  576.         *blank=0;
  577.     
  578.     typesList[0] = recordType;
  579.     
  580.     recCopyInfo.gotOne = false;
  581.     recCopyInfo.creationID = returnedCID;
  582.     recCopyInfo.recordName = recordName;
  583.     
  584.     dirBlock.enumerateGetPB.serverHint.aNet = 0;
  585.     dirBlock.enumerateGetPB.serverHint.aNode = 0;
  586.     dirBlock.enumerateGetPB.serverHint.aSocket = 0;
  587.     dirBlock.enumerateGetPB.dsRefNum = dsRef;
  588.     dirBlock.enumerateGetPB.identity = gLocalIdentity;
  589.     dirBlock.enumerateGetPB.clientData = (long)&recCopyInfo;
  590.     dirBlock.enumerateGetPB.aRLI = nil;
  591.     dirBlock.enumerateGetPB.startingPoint = nil;
  592.     dirBlock.enumerateGetPB.sortBy = kSortByName;
  593.     dirBlock.enumerateGetPB.sortDirection = kSortForwards;
  594.     dirBlock.enumerateGetPB.typesList = typesList;
  595.     dirBlock.enumerateGetPB.typeCount = 1;
  596.     dirBlock.enumerateGetPB.enumFlags = kEnumDistinguishedNameMask;
  597.     dirBlock.enumerateGetPB.includeStartingPoint = false;
  598.     dirBlock.enumerateGetPB.getBuffer = buff;
  599.     dirBlock.enumerateGetPB.getBufferSize = kRecordBufferSize;
  600.     dirBlock.enumerateParsePB.eachEnumSpec = GatewayDirEnumCallback;
  601.     
  602.     err = DirEnumerateGet(&dirBlock,false);
  603.     if (err==noErr || err==kOCEMoreData)
  604.         err = DirEnumerateParse(&dirBlock,false);
  605.  
  606.     DisposPtr(buff);
  607.     
  608.     if ((err==noErr) && !recCopyInfo.gotOne)
  609.         err = kNoRecords;
  610.         
  611.     return err;
  612. }
  613.  
  614.  
  615. pascal Boolean GatewayDirEnumCallback(long clientData, const DirEnumSpec *enumSpec)
  616. {
  617.     RecordCopyInfo *recCopyInfo;
  618.     
  619.     recCopyInfo = (RecordCopyInfo *)clientData;
  620.     
  621.     if (!recCopyInfo->gotOne && enumSpec->enumFlag & kEnumDistinguishedNameMask &&
  622.         OCEEqualRString(recCopyInfo->recordName,enumSpec->u.recordIdentifier.recordName,kOCERecordOrDNodeName)) {
  623.  
  624.         OCECopyCreationID(&enumSpec->u.recordIdentifier.cid,recCopyInfo->creationID);
  625.         recCopyInfo->gotOne = true;
  626.         return true;
  627.         
  628.     }
  629.     return false;
  630. }
  631.  
  632.  
  633. OSErr DeleteSingleAttributeValue(CreationID *cid,AttributeTypePtr attrType,
  634.         AttributeCreationID *attrCID)
  635. {
  636.     DirParamBlock dirBlock;
  637.     RecordID recordID;
  638.     OSErr err;
  639.     Attribute attribute;
  640.     
  641.     MakePersonalRecordID(&recordID,cid);
  642.     OCECopyRString((RStringPtr)attrType,(RStringPtr)&attribute.attributeType,kAttributeTypeMaxBytes);
  643.     OCECopyCreationID(attrCID,&attribute.cid);
  644.     
  645.     ClearBuffer(&dirBlock,sizeof(DirParamBlock));
  646.     
  647.     dirBlock.deleteAttributeValuePB.dsRefNum = gAOCESetupDSRef;    // working with PAB
  648.     dirBlock.deleteAttributeValuePB.identity = gLocalIdentity;
  649.     dirBlock.deleteAttributeValuePB.aRecord = &recordID;
  650.     dirBlock.deleteAttributeValuePB.attr = &attribute;
  651.     err = DirDeleteAttributeValue(&dirBlock,false);
  652.     return err;
  653. }
  654.  
  655.  
  656. void CloseGatewayStuff(void)
  657. {
  658. }
  659.  
  660.  
  661. OSErr InitAOCEStuff(void)
  662. {
  663.     return noErr;
  664. }
  665.  
  666.  
  667. void CloseAOCEStuff(void)
  668. {
  669.     ExitAuthStuff();
  670. }
  671.  
  672.  
  673. // HasAOCE
  674. //
  675. // returns true only of AOCE is available and running
  676. //
  677. Boolean HasAOCE(void)
  678. {
  679.     OSErr err;
  680.     long response;
  681.     
  682.     if (!TrapAvailable(_GestaltDispatch))
  683.         return false;
  684.     
  685.     err = Gestalt(gestaltOCEToolboxAttr,&response);
  686.     if (err!=noErr)
  687.         return false;
  688.         
  689.     return (response && (response << gestaltOCETBAvailable));
  690. }
  691.  
  692.  
  693. // MakePersonalRecordID
  694. //
  695. // this convenience function fills in a RecordID given a creation ID, since a fully specified
  696. // record ID for a personal directory contains only a creation ID
  697. //
  698. void MakePersonalRecordID(RecordID *recordID,CreationID *creationID)
  699. {
  700.     recordID->rli = nil;
  701.     OCECopyCreationID(creationID,&recordID->local.cid);
  702.     recordID->local.recordName = nil;
  703.     recordID->local.recordType = nil;
  704. }
  705.  
  706.  
  707. // GetSlotSpecFromID
  708. //
  709. // given a slot ID this function returns the corresponding slot info record which we store
  710. // for each slot
  711. //
  712. SlotSpec *GetSlotSpecFromID(short slotID)
  713. {
  714.     short index;
  715.     
  716.     for (index=0; index<gNumSlots; index++)
  717.         if (gSlotDatabase[index].slotID==slotID)
  718.             return &gSlotDatabase[index];
  719.     
  720.     return nil;
  721. }
  722.  
  723.  
  724. void MacToMailTime(unsigned long macTime,MailTime *mailTime)
  725. {
  726.     mailTime->time = macTime + (8*60*60);    // assume pacific time for now (hack)
  727.     mailTime->offset = (8*60*60);
  728. }
  729.  
  730.  
  731. void r2cString (RString *rStr,char *cStr)
  732. {
  733.     StringPtr pStr;
  734.     
  735.     pStr = OCERToPString(rStr);
  736.     pstrcpy((StringPtr)cStr,pStr);
  737.     p2cstr((StringPtr)cStr);
  738. }
  739.  
  740.  
  741. // this routine copies as many bytes from rstr1 to rstr2, truncating rstr2 if there isn't
  742. // enough space
  743. //
  744. OSErr OCECopyFitRString (RString *str1, RString *str2, unsigned short str2Length)
  745. {
  746.     unsigned short saveLength;
  747.     OSErr err;
  748.     
  749.     saveLength = str1->dataLength;
  750.     
  751.     if (str2Length<str1->dataLength)
  752.         str1->dataLength = str2Length;
  753.     
  754.     err = OCECopyRString(str1,str2,str2Length);
  755.     str1->dataLength = saveLength;
  756.     return err;
  757. }
  758.  
  759.  
  760. pascal void MSAMCompletion(MSAMParam *gwp)
  761. {
  762.     long saveA5;
  763.     
  764.     saveA5 = SetA5((long)gwp->header.saveA5);
  765.  
  766.     gWakeUpSecondary = true;                    // set a flag in case we get caught
  767.     WakeUpProcess(&gOurPSN);                    // in between check and WaitNextEvent...
  768.  
  769.     SetA5(saveA5);
  770. }
  771.